bitkeeper revision 1.1081.1.1 (40f552eaWV4viomXWEuk8dzfLHid7g)
authormjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Wed, 14 Jul 2004 15:36:10 +0000 (15:36 +0000)
committermjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Wed, 14 Jul 2004 15:36:10 +0000 (15:36 +0000)
Change to new restart model.

.rootkeys
tools/examples/xmdefaults
tools/examples/xmnetbsd
tools/python/xen/xend/XendClient.py
tools/python/xen/xend/XendDomain.py
tools/python/xen/xend/XendDomainInfo.py
tools/python/xen/xend/server/SrvDomain.py
tools/python/xen/xm/create.py
tools/python/xen/xm/destroy.py [new file with mode: 0644]
tools/python/xen/xm/main.py

index f11d07c06a216802398760acecf6523c8ff9bc40..dc54a492ff787c245c0f940cbeed10990e933047 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py
 40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py
 40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py
+40f552eariuUSB9TWqCPnDLz5zvxMw tools/python/xen/xm/destroy.py
 40e41cd2w0I4En6qrJn4em8HkK_oxQ tools/python/xen/xm/help.py
 40cf2937isyS250zyd0Q2GuEDoNXfQ tools/python/xen/xm/main.py
 40cf2937PSslwBliN1g7ofDy2H_RhA tools/python/xen/xm/opts.py
index 2c417a7cf888fa4f62ecf3787beaeb3051c82ce3..ebb894d53ef628552bf5a85c69eda0f6ca4522c4 100644 (file)
@@ -91,8 +91,11 @@ root = "/dev/sda1 ro"
 extra = "4 VMID=%d usr=/dev/sda6" % vmid
 
 #----------------------------------------------------------------------------
-# Set according to whether you want the domain  restarted when it exits.
-# The default is False.
-#autorestart = True
+# Set according to whether you want the domain restarted when it exits.
+# The default is 'onreboot', which restarts the domain when it shuts down
+# with exit code reboot.
+# Other values are 'always', and 'never'.
+
+#restart = 'onreboot'
 
 #============================================================================
index e62de6174eb353f8bdde736b2d6fb6a6ff700352..f2a525d2e9cc669c45fc3264b02f560a81eb707b 100644 (file)
@@ -94,8 +94,10 @@ extra = "4 VMID=%d bootdev=xennet0" % vmid
 
 
 #----------------------------------------------------------------------------
-# Set according to whether you want the domain  restarted when it exits.
-# The default is False.
-#autorestart = True
-
+# Set according to whether you want the domain restarted when it exits.
+# The default is 'onreboot', which restarts the domain when it shuts down
+# with exit code reboot.
+# Other values are 'always', and 'never'.
+#
+#restart = 'onreboot'
 #============================================================================
index 91ba071dc00f38de584380df27db3e75c9fbb8cb..538f84c3a9218c775318305b150a97207df718c1 100644 (file)
@@ -256,9 +256,10 @@ class Xend:
                          {'op'      : 'shutdown',
                           'reason'  : reason })
 
-    def xend_domain_destroy(self, id):
+    def xend_domain_destroy(self, id, reason):
         return xend_call(self.domainurl(id),
-                         {'op'      : 'destroy' })
+                         {'op'      : 'destroy',
+                          'reason'  : reason })
 
     def xend_domain_save(self, id, filename):
         return xend_call(self.domainurl(id),
index 2f0a7680c261415df0a1f8b80f908989b7aee02f..51d52f1acc3b43f96041e17629f58e73b61a6da4 100644 (file)
@@ -378,9 +378,9 @@ class XendDomain:
     
     def domain_shutdown(self, id, reason='poweroff'):
         """Shutdown domain (nicely).
-         - poweroff: domain will restart if has autorestart set.
-         - reboot: domain will restart.
-         - halt: domain will not restart (even if has autorestart set).
+         - poweroff: restart according to exit code and restart mode
+         - reboot:   restart on exit
+         - halt:     do not restart
 
          Returns immediately.
 
@@ -388,12 +388,13 @@ class XendDomain:
         @param reason: shutdown type: poweroff, reboot, suspend, halt
         """
         dom = int(id)
+        id = str(id)
         if dom <= 0:
             return 0
         if reason == 'halt':
             self.domain_restart_cancel(id)
         else:
-            self.domain_restart_schedule(id, reason)
+            self.domain_restart_schedule(id, reason, set=1)
         eserver.inject('xend.domain.shutdown', [id, reason])
         if reason == 'halt':
             reason = 'poweroff'
@@ -401,21 +402,24 @@ class XendDomain:
         self.refresh_schedule()
         return val
 
-    def domain_restart_schedule(self, id, reason):
+    def domain_restart_schedule(self, id, reason, set=0):
         """Schedule a restart for a domain if it needs one.
 
         @param id:     domain id
         @param reason: shutdown reason
         """
+        print 'domain_restart_schedule>', id, reason, set
         dominfo = self.domain.get(id)
-        if not dominfo or id in self.restarts:
-            # Don't schedule if unknown or already there.
+        if not dominfo:
+            return
+        if id in self.restarts:
             return
-        restart = ((reason == 'reboot') or
-                   (reason == 'poweroff' and dominfo.autorestart))
+        if set and reason == 'reboot':
+            dominfo.restart_mode = XendDomainInfo.RESTART_ALWAYS
+        restart = dominfo.restart_needed(reason)
         if restart:
-            # Clear autorestart flag to avoid multiple restarts.
-            dominfo.autorestart = 0
+            # Avoid multiple restarts.
+            dominfo.restart_mode = XendDomainInfo.RESTART_NEVER
             self.restarts[id] = dominfo.config
             print 'Scheduling restart for domain:', id, dominfo.name
             self.domain_restarts_schedule()
@@ -427,7 +431,7 @@ class XendDomain:
         """
         dominfo = self.domain.get(id)
         if dominfo:
-            dominfo.autorestart = 0
+            dominfo.restart_mode = XendDomainInfo.RESTART_NEVER
         if id in self.restarts:
             del self.restarts[id]
 
@@ -474,13 +478,18 @@ class XendDomain:
             val = xc.domain_destroy(dom=dom)
         return val       
 
-    def domain_destroy(self, id):
+    def domain_destroy(self, id, reason='halt'):
         """Terminate domain immediately.
-        Cancels any restart for the domain.
+        - halt:   cancel any restart for the domain
+        - reboot  schedule a restart for the domain
 
         @param id: domain id
         """
-        self.domain_restart_cancel(id)
+        id = str(id)
+        if reason == 'halt':
+            self.domain_restart_cancel(id)
+        elif reason == 'reboot':
+            self.domain_restart_schedule(id, reason, set=1)
         val = self.final_domain_destroy(id)
         self.refresh_schedule()
         return val
index be7803f7212b3f79cd71f96bfb7338c6a55a7159..d63034f3ffa2fbd329298169bd364c0a45014060 100644 (file)
@@ -50,6 +50,16 @@ shutdown_reasons = {
     DOMAIN_REBOOT  : "reboot",
     DOMAIN_SUSPEND : "suspend" }
 
+RESTART_ALWAYS   = 'always'
+RESTART_ONREBOOT = 'onreboot'
+RESTART_NEVER    = 'never'
+
+restart_modes = [
+    RESTART_ALWAYS,
+    RESTART_ONREBOOT,
+    RESTART_NEVER,
+    ]
+
 def shutdown_reason(code):
     """Get a shutdown reason from a code.
 
@@ -117,7 +127,12 @@ def lookup_disk_uname(uname):
 def make_disk(dom, uname, dev, mode, recreate=0):
     """Create a virtual disk device for a domain.
 
-    @returns Deferred
+    @param dom:      domain id
+    @param uname:    device to export
+    @param dev:      device name in domain
+    @param mode:     read/write mode
+    @param recreate: recreate flag (after xend restart)
+    @return: deferred
     """
     segments = lookup_disk_uname(uname)
     if not segments:
@@ -234,7 +249,6 @@ def vm_create(config):
     returns Deferred
     raises VmError for invalid configuration
     """
-    print 'vm_create>'
     vm = XendDomainInfo()
     return vm.construct(config)
 
@@ -289,28 +303,21 @@ def append_deferred(dlist, v):
 
 def _vm_configure1(val, vm):
     d = vm.create_devices()
-    #print '_vm_configure1> made devices...'
     def cbok(x):
-        #print '_vm_configure1> cbok', x
         return x
     d.addCallback(cbok)
     d.addCallback(_vm_configure2, vm)
-    #print '_vm_configure1<'
     return d
 
 def _vm_configure2(val, vm):
-    #print '>callback _vm_configure2...'
     d = vm.configure_fields()
     def cbok(results):
-        #print '_vm_configure2> cbok', results
         return vm
     def cberr(err):
-        #print '_vm_configure2> cberr', err
         vm.destroy()
         return err
     d.addCallback(cbok)
     d.addErrback(cberr)
-    #print '<_vm_configure2'
     return d
 
 class XendDomainInfo:
@@ -341,7 +348,7 @@ class XendDomainInfo:
         #todo: set to migrate info if migrating
         self.migrate = None
         #Whether to auto-restart
-        self.autorestart = 0
+        self.restart_mode = RESTART_ONREBOOT
 
     def setdom(self, dom):
         self.dom = int(dom)
@@ -381,8 +388,7 @@ class XendDomainInfo:
             state = run + block + stop + susp + crash
             sxpr.append(['state', state])
             if self.info['shutdown']:
-                reasons = ["poweroff", "reboot", "suspend"]
-                reason = reasons[self.info['shutdown_reason']]
+                reason = shutdown_reason(self.info['shutdown_reason'])
                 sxpr.append(['shutdown_reason', reason])
             sxpr.append(['cpu', self.info['cpu']])
             sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
@@ -398,8 +404,7 @@ class XendDomainInfo:
         try:
             self.name = sxp.child_value(config, 'name')
             self.memory = int(sxp.child_value(config, 'memory', '128'))
-            if sxp.child(config, 'autorestart', None):
-                self.autorestart = 1
+            self.configure_restart()
             self.configure_backends()
             image = sxp.child_value(config, 'image')
             if image is None:
@@ -413,7 +418,6 @@ class XendDomainInfo:
             image_handler(self, image)
             deferred = self.configure()
             def cbok(x):
-                print 'vm_create> cbok', x
                 return x
             def cberr(err):
                 self.destroy()
@@ -424,7 +428,6 @@ class XendDomainInfo:
             # Catch errors, cleanup and re-raise.
             self.destroy()
             raise
-        print 'vm_create<'
         return deferred
 
     def config_devices(self, name):
@@ -514,7 +517,6 @@ class XendDomainInfo:
     def cleanup(self):
         """Cleanup vm resources: release devices.
         """
-        print 'cleanup>', self.dom
         self.state = self.STATE_TERMINATED
         self.release_devices()
 
@@ -526,7 +528,6 @@ class XendDomainInfo:
     def release_devices(self):
         """Release all vm devices.
         """
-        print 'release_devices>', self.dom
         self.release_vifs()
         self.release_vbds()
         self.devices = {}
@@ -534,7 +535,6 @@ class XendDomainInfo:
     def release_vifs(self):
         """Release vm virtual network devices (vifs).
         """
-        print 'release_vifs>', self.dom
         if self.dom is None: return
         ctrl = xend.netif_get(self.dom)
         if ctrl:
@@ -543,7 +543,6 @@ class XendDomainInfo:
     def release_vbds(self):
         """Release vm virtual block devices (vbds).
         """
-        print 'release_vbds>', self.dom
         if self.dom is None: return
         ctrl = xend.blkif_get(self.dom)
         if ctrl:
@@ -574,7 +573,7 @@ class XendDomainInfo:
         memory = self.memory
         name = self.name
         cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
-        print 'init_domain>', memory, name, cpu
+        #print 'init_domain>', memory, name, cpu
         dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
         if dom <= 0:
             raise VmError('Creating domain failed: name=%s memory=%d'
@@ -589,7 +588,7 @@ class XendDomainInfo:
             print 'Warning: kernel cmdline too long'
         dom = self.dom
         buildfn = getattr(xc, '%s_build' % ostype)
-        print 'build_domain>', ostype, dom, kernel, cmdline, ramdisk
+        #print 'build_domain>', ostype, dom, kernel, cmdline, ramdisk
         flags = 0
         if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
         if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
@@ -612,15 +611,12 @@ class XendDomainInfo:
         cmdline kernel commandline
         vifs_n  number of network interfaces
         """
-        print 'create_domain>', ostype, kernel
         if not self.recreate:
             if not os.path.isfile(kernel):
                 raise VmError('Kernel image does not exist: %s' % kernel)
             if ramdisk and not os.path.isfile(ramdisk):
                 raise VmError('Kernel ramdisk does not exist: %s' % ramdisk)
-        print 'create-domain> init_domain...'
         self.init_domain()
-        print 'create_domain>', 'dom=', self.dom
         self.console = xendConsole.console_create(self.dom)
         self.build_domain(ostype, kernel, ramdisk, cmdline, vifs_n)
         self.image = kernel
@@ -633,7 +629,6 @@ class XendDomainInfo:
         returns Deferred
         raises VmError for invalid devices
         """
-        print '>create_devices'
         dlist = []
         devices = sxp.children(self.config, 'device')
         index = {}
@@ -650,7 +645,6 @@ class XendDomainInfo:
             append_deferred(dlist, v)
             index[dev_name] = dev_index + 1
         deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
-        print '<create_devices'
         return deferred
 
     def device_create(self, dev_config):
@@ -686,6 +680,21 @@ class XendDomainInfo:
             self.config.remove(['device', dev_config])
         dev.destroy()
 
+    def configure_restart(self):
+        r = sxp.child_value(self.config, 'restart', RESTART_ONREBOOT)
+        if r not in restart_modes:
+            raise VmError('invalid restart mode: ' + str(r))
+        self.restart_mode = r;
+
+    def restart_needed(self, reason):
+        if self.restart_mode == RESTART_NEVER:
+            return 0
+        if self.restart_mode == RESTART_ALWAYS:
+            return 1
+        if self.restart_mode == RESTART_ONREBOOT:
+            return reason == 'reboot'
+        return 0
+
     def configure_backends(self):
         """Set configuration flags if the vm is a backend for netif of blkif.
         """
@@ -807,7 +816,7 @@ def vm_image_netbsd(vm, image):
     args = sxp.child_value(image, "args")
     if args:
         cmdline += " " + args
-    ramdisk = sxp.child_value(image, "ramdisk")
+    ramdisk = sxp.child_value(image, "ramdisk", '')
     vifs = vm.config_devices("vif")
     vm.create_domain("netbsd", kernel, ramdisk, cmdline, len(vifs))
     return vm
@@ -830,7 +839,6 @@ def vm_dev_vif(vm, val, index):
         dev = xend.netif_dev(vm.dom, vif)
         dev.vifctl('up', vmname=vm.name)
         vm.add_device('vif', dev)
-        print 'vm_dev_vif> created', dev
         return id
     defer.addCallback(fn)
     return defer
index a3ec017622a7f391c4b6af55dab9e5d3b15676f2..eed90b7feb5fd2e19cb6f96514e0cac4fad5ca08 100644 (file)
@@ -50,7 +50,10 @@ class SrvDomain(SrvDir):
         return val
 
     def op_destroy(self, op, req):
-        val = self.xd.domain_destroy(self.dom.id)
+        fn = FormFn(self.xd.domain_destroy,
+                    [['dom', 'int'],
+                     ['reason', 'str']])
+        val = fn(req.args, {'dom': self.dom.id})
         req.setHeader("Location", "%s/.." % req.prePathURL())
         return val
 
@@ -220,7 +223,12 @@ class SrvDomain(SrvDir):
         req.write('<form method="post" action="%s">' % url)
         req.write('<input type="submit" name="op" value="unpause">')
         req.write('<input type="submit" name="op" value="pause">')
+        req.write('</form>')
+
+        req.write('<form method="post" action="%s">' % url)
         req.write('<input type="submit" name="op" value="destroy">')
+        req.write('<input type="radio" name="reason" value="halt" checked>Halt')
+        req.write('<input type="radio" name="reason" value="reboot">Reboot')
         req.write('</form>')
 
         req.write('<form method="post" action="%s">' % url)
index c4e2567fe22f62a01fadfba7487b4735729c02e4..7c9dcb3db8b19799f629a010bfe1872674d4896b 100644 (file)
@@ -97,9 +97,13 @@ gopts.var('memory', val='MEMORY',
          fn=set_value, default=128,
          use="Domain memory in MB.")
 
-gopts.var('autorestart', val='no|yes',
-         fn=set_bool, default=0,
-         use="Whether to restart the domain on exit.")
+gopts.var('restart', val='onreboot|always|never',
+         fn=set_value, default=None,
+         use="""Whether the domain should be restarted on exit.
+         - onreboot: restart on exit with shutdown code reboot
+         - always:   always restart on exit, ignore exit code
+         - never:    never restart on exit, ignore exit code
+         """)
 
 gopts.var('blkif', val='no|yes',
           fn=set_bool, default=0,
@@ -294,8 +298,8 @@ def make_config(vals):
         config.append(['backend', ['blkif']])
     if vals.netif:
         config.append(['backend', ['netif']])
-    if vals.autorestart:
-        config.append(['autorestart'])
+    if vals.restart:
+        config.append(['restart', vals.restart])
     
     configure_image(config, vals)
     config_devs = []
diff --git a/tools/python/xen/xm/destroy.py b/tools/python/xen/xm/destroy.py
new file mode 100644 (file)
index 0000000..73df69d
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""Destroy a domain.
+"""
+
+from xen.xend.XendClient import server
+from xen.xm.opts import *
+
+gopts = Opts(use="""[options] [DOM]
+
+Destroy a domain, optionally restarting it.
+""")
+
+gopts.opt('help', short='h',
+         fn=set_true, default=0,
+         use="Print this help.")
+
+gopts.opt('reboot', short='R',
+          fn=set_true, default=0,
+          use='Destroy and restart.')
+
+def main(argv):
+    opts = gopts
+    args = opts.parse(argv)
+    if opts.vals.help:
+        opts.usage()
+        return
+    if len(args) < 1: opts.err('Missing domain')
+    dom = args[0]
+    try:
+        domid = int(dom)
+    except:
+        opts.err('Invalid domain: ' + dom)
+    if opts.vals.reboot:
+        mode = 'reboot'
+    else:
+        mode = 'halt'
+    server.xend_domain_destroy(domid, mode)
+    
+        
index e624447955745704cbcbf518af02a566b923b041..5c1c5440739bde02a159de414dbcff1a5520ad6a 100644 (file)
@@ -11,7 +11,7 @@ from xen.xend import PrettyPrint
 from xen.xend import sxp
 from xen.xend.XendClient import XendError, server
 from xen.xend.XendClient import main as xend_client_main
-from xen.xm import create, shutdown
+from xen.xm import create, destroy, shutdown
 
 class Prog:
     """Base class for sub-programs.
@@ -268,13 +268,10 @@ class ProgDestroy(Prog):
     info = """Terminate a domain immediately."""
 
     def help(self, args):
-        print args[0], 'DOM'
-        print '\nTerminate domain DOM immediately.'
+        destroy.main([args[0], '-h'])
 
     def main(self, args):
-        if len(args) < 2: self.err("%s: Missing domain" % args[0])
-        dom = args[1]
-        server.xend_domain_destroy(dom)
+        destroy.main(args)
 
 xm.prog(ProgDestroy)